home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 December / EnigmA AMIGA RUN 23 (1997)(G.R. Edizioni)(IT)[!][issue 1997-12][EAR-CD VII].iso / listati / readiff.c < prev    next >
C/C++ Source or Header  |  1997-11-11  |  19KB  |  435 lines

  1. //**********************************************************************
  2. //*                                                                    *
  3. //*      Algoritmo per la decodifica di immagini IFF-ILBM              *
  4. //*                                                                    *
  5. //**********************************************************************
  6.  
  7.  
  8. #include <exec/memory.h>
  9. #include <exec/types.h>
  10. #include <graphics/gfxbase.h>
  11. #include <intuition/intuition.h>
  12. #include <stdio.h>
  13.  
  14. #include <clib/exec_protos.h>
  15. #include <clib/graphics_protos.h>
  16. #include <clib/intuition_protos.h>
  17.  
  18. #define LIB_VERSION      39
  19. #define DIM_MSG          20
  20. #define NUM_MSG          10
  21. #define DIM_RICERCA      2000
  22. #define PUB_PULITA       MEMF_PUBLIC|MEMF_CLEAR
  23.  
  24. #define ERR_MEMORIA      1
  25. #define ERR_LIBS         2
  26. #define ERR_TIPO_FILE    3
  27.  
  28. #define ID_IFF_FORM 0x464F524D   //id header IFF (parola "FORM")
  29. #define ID_IFF_ILBM 0x494C424D   //id iff (parola "ILBM")
  30. #define ID_IFF_BMHD 0x424D4844   //id IFF (parola "BMHD")
  31. #define ID_IFF_CMAP 0x434D4150   //id iff (parola "CMAP")
  32. #define ID_IFF_CAMG 0x43414D47   //id IFF (parola "CAMG")
  33. #define ID_IFF_BODY 0x424F4459   //id iff (parola "BODY")
  34.  
  35.  
  36. struct chunk {
  37.        ULONG id;
  38.        ULONG dimens;
  39.        UBYTE *buffer;
  40.   };// CMAP CAMG e BODY hanno praticamente la stessa struttura
  41.  
  42. struct chunk_bmhd {
  43.    ULONG id;
  44.        ULONG dimens;
  45.        UWORD lx_immagine;
  46.        UWORD ly_immagine;
  47.        UWORD x_bitmap;
  48.        UWORD y_bitmap;
  49.        UBYTE piani;
  50.        UBYTE decodifica;
  51.        UBYTE compressione;
  52.        UWORD colore_trasparente;
  53.        UBYTE x_aspetto_pixel;
  54.        UBYTE y_aspetto_pixel;
  55.        UWORD lx_schermo;
  56.        UWORD ly_schermo;
  57.   };
  58.  
  59. struct Library     *intuibase=NULL,
  60.                    *gfxbase=NULL;
  61. struct chunk       *cmap=NULL,
  62.                    *camg=NULL,
  63.                    *body=NULL;
  64. struct chunk_bmhd  bmhd; //BMHD ha grandezza fissa
  65.  
  66.  
  67. //  ##########  dichiarazioni delle funzioni C usate  #################
  68.  
  69. void   Dealloca_Buffers();
  70. oULONG  Find_Id (ULONG,UBYTE*,ULONG);
  71. struct chunk* File_To_Buffer(FILE*,ULONG,UBYTE*,ULONG);
  72. int    DecodeIff(FILE*);
  73. void   CloseLibs();
  74.  
  75. //  ##########  inizio listato  ######################################
  76.  
  77. int main (int argc,char **argv)
  78. {
  79.   FILE* finput = NULL;
  80.   int numero_files=1;
  81.   if ((intuibase=(struct Library*)OpenLibrary("intuition.library",LIB_VERSION))==NULL) return (ERR_LIBS);
  82.   // struct Library* Openlibrary(char* nome,ULONG versione); (LIBRERIA EXEC)
  83.   // La funzione OpenLibrary apre una libreria di sistema.
  84.   // Accetta come argomenti il nome della libreria da aprire ("nome") e la versione
  85.   // della stessa ("versione").
  86.   // in caso di riuscita apertura della lireria restituisce l'indirizzo
  87.   // della struttura libreria appena allocata,viceversa 0 (NULL).
  88.   if ((gfxbase  =(struct Library*)OpenLibrary("graphics.library",LIB_VERSION))==NULL)
  89.   {
  90.      CloseLibrary(intuibase);
  91.      return (ERR_LIBS);
  92.   }
  93.   for (numero_files=1;numero_files < argc;numero_files++)
  94.      if ((finput = fopen(argv[numero_files],"r")))
  95.      // FILE* fopen(char* nome,char* modo);  (PORTABILITA' ANSI C)
  96.      // fopen apre un file. come primo argomento accetta un char* che
  97.      // rappresenta il percorso e il nome del del file nel disco (es. "ram:t/pippo.txt")
  98.      // mentre come secondo un char* che rappresenta il modo di accesso.
  99.      // I principali modi di accesso sono:
  100.      //    "r" ,file a sola lettura
  101.      //    "w" ,file a sola scrittura(se non esise viene creato)
  102.      //    "a" ,file attaccabile(cioè se il file esiste allora la funzione
  103.      //         restituirà un puntatore alla fine del file in modo da poter
  104.      //         andare a vanti con la scrittura).
  105.      // Le opzioni sono combinabili tra loro quindi datevi un'occhiata ai docs
  106.      // per maggiori delucidazioni o se avete qualche esigenza speciale.
  107.      // Se il file non esiste allora se come modo d'accesso abbiamo inserito
  108.      // "r" verrà restituito NULL, altrimenti verrà creato un nuovo file e
  109.      // verrà restituito un FILE*.
  110.      {
  111.        rewind ( finput );
  112.        // void rewind(FILE* file); (PORTABILITA' ANSI C)
  113.        // rewind porta il azzera il puntatore del file, cioè lo fa puntare
  114.        // all'inizio dell'archivio.
  115.        DecodeIff ( finput );
  116.        fclose ( finput );
  117.        // void fclose(FILE* file);(PORTABILITA' ANSI C)
  118.        // fclose chiude il file. Tutto qui!
  119.      }
  120.   if (intuibase) CloseLibrary (intuibase);
  121.     // void CloseLibrary(struct Library* libreria); (Libreria EXEC)
  122.     // Dovrei forse dirvi a cosa serve questa funzione?
  123.   if (gfxbase)   CloseLibrary (gfxbase);
  124.   return(0);
  125. }
  126.  
  127. void Dealloca_Buffers()
  128.  // Questa funzione dealloca i buffer puntati dalle nostre varibili globali,
  129.  // e successivamente dealloca le strutture chunk.
  130. {
  131.   if (cmap->buffer) FreeMem(cmap->buffer,cmap->dimens);
  132.  // void FreeMem(APTR ptr_memoria,ULONG dimensione)  (libreria EXEC)
  133.  // FreeMem libera una quantità di bytes a partire dalla locazione puntata
  134.  // dall' APTR per un totale di bytes memorizzato in "dimensione"
  135.   if (camg->buffer) FreeMem(camg->buffer,camg->dimens);
  136.   if (body->buffer) FreeMem(body->buffer,body->dimens);
  137.   if (cmap)         FreeMem(cmap,sizeof(struct chunk));
  138.   if (camg)         FreeMem(camg,sizeof(struct chunk));
  139.   if (body)         FreeMem(body,sizeof(struct chunk));
  140.   cmap=NULL;camg=NULL;body=NULL;
  141. }
  142.  
  143. ULONG Find_Id(ULONG id, UBYTE* buffer,ULONG dimens_buffer)
  144.   // Questa funzione permette di cercare l'header in un buffer in memoria.
  145.   // "carattere" contiene la prima "lettera" che compone l'ID.
  146.   // Il resto del codice è una normale ricerca sequenziale.
  147.   // La funzione ritorna la posizione del chunk nel buffer (e quindi nel
  148.   // file) in caso di successo e il valore -1 in caso di insuccesso.
  149. {
  150.   ULONG  posiz=0;
  151.   UBYTE  trovato=0;
  152.   UBYTE  carattere=UBYTE(id>>24);
  153.   ULONG* indice=(ULONG*)buffer;
  154.   while ((posiz < dimens_buffer) & (!trovato))
  155.   {
  156.     if (carattere == (*indice>>24)) if (*indice == id) trovato=1;
  157.     ((UBYTE*)indice)++;
  158.     if (!trovato) posiz++;
  159.   }
  160.   if (trovato) return(posiz);
  161.   return(-1);
  162. }
  163.  
  164. struct chunk* File_To_Buffer(FILE *finput,ULONG id,UBYTE* buffer,ULONG dimens)
  165.  
  166.  // Questa funzione crea il chunk vero e proprio trasferendo i dati dal
  167.  // file in memoria. La funzione ritorna il PUNTATORE alla struttura
  168.  // chunk in caso di successo, 0 (NULL) altrimenti.
  169. {
  170.   struct chunk *appo=NULL;
  171.   ULONG  posizione_id=0;
  172.   if ((appo=AllocMem(sizeof(struct chunk),MEMF_PUBLIC))==NULL) return(0);
  173.   // APTR AllocMem(ULONG dimensione,ULONG tipo_memoria); (libreria EXEC)
  174.   // AllocMem alloca una quantità di bytes pari al valore della prima ULONG
  175.   // nel tipo di memoria specificato dalla seconda.
  176.   // i tipi di memoria possono essere:
  177.   //  "MEMF_CHIP"   (alloca nella chip ram)
  178.   //  "MEMF_FAST"   (alloca nella fast ram)
  179.   //  "MEMF_PUBLIC" (alloca nella memoria pubblica,cioè memoria di solito
  180.   //                 usata per allocare task interrupt o qualcos'altro).
  181.   //  "MEMF_CLEAR"  (i bytes allocati vengono azzerati).
  182.   // I tipi possono essere "mescolati" tra loro (cioè si puo' fare
  183.   // AllocMem(pippo, MEMF_PUBLIC | MEMF_CLEAR );
  184.   posizione_id = Find_Id(id,buffer,dimens);
  185.   if (posizione_id == (-1)) goto errore_fatale;
  186.   fseek(finput,posizione_id,SEEK_SET);
  187.   //  int fseek(FILE* file,long posizione,int tipo_spostamento) (PORTABILITA' ANSI C)
  188.   //  fseek sposta il puntatore al FILE* di tot bytes (avanti o indietro)
  189.   //  indicati nel valore della long.int specifica da che punto spostarsi
  190.   //  int = SEEK_SET impone al file di spostarsi di tot bytes dall'inizio del file
  191.   //  int = SEEK_CUR dalla posizione corrente del puntatore
  192.   //  int = SEEK_END dalla fine del file.
  193.   //  se lo spostamento ha successo la funzione restituisce il valore 0
  194.   //  un qualsiasi altro valore altrimenti.
  195.   fread((char*)&appo->id,1,4,finput);
  196.   //  long fread(void* buffer,long dim_blocco,long num_blocchi,FILE* file) (PORTABILITA' ANSI C)
  197.   //  la funzione fread legge da un FILE* un certo numero di blocchi indicato
  198.   //  nella seconda long,dove ogni blocco è definito in dimensioni
  199.   //  dalla prima long,e trasferisce i bytes letti in un vettore.
  200.   //  Il trasferimento avviene dalla posizione puntata dal FILE* e alla fine
  201.   //  della funzione il FILE* punterà blocco successivo dell'ultimo blocco letto.
  202.   //  La funzione restituisce il numero di blocchi effettivamente letti dal
  203.   //  file (in pratica serve a segnalare se arriviamo alla fine del file
  204.   //  oppure se c'e' stato qualche errore).
  205.   //
  206.   //  es: Nel programma utilizziamo fread((char*)&appo->id,1,4,finput);
  207.   //      ciò significa che:
  208.   //          "(char*)&appo->id" è il vettore dove andranno trasferiti i bytes letti
  209.   //          "1"  è la dimensione in bytes dei blocchi da trasferire
  210.   //               (se fosse stata "2" allora avremmo trasferito una WORD alla volta,
  211.   //                "4" una LONG e "size_of(struct chunk_bmhd)" un numero
  212.   //                di bytes pari a quelli usati per definire la struttura
  213.   //                chunk bmhd, ecc).
  214.   //          "4"  è il numero di blocchi da leggere (in questo caso 4 bytes,
  215.   //               o meglio, 4 char(anche se in pratica non cambia nulla)).
  216.   //          "finput" è il puntatore al file.
  217.   fread((char*)&appo->dimens,1,4,finput);
  218.   if ((appo->buffer=AllocMem(appo->dimens,MEMF_PUBLIC))==NULL) goto errore_fatale;
  219.   fread((char*)appo->buffer,1,appo->dimens,finput);
  220.   return(appo);
  221.   errore_fatale: // La memoria è finita! Andate in pace.
  222.   FreeMem(appo,sizeof(struct chunk));
  223.   return(0);
  224. }
  225.  
  226. int DecodeIff(FILE* finput)
  227. {
  228.   struct Screen     *schermo=NULL;
  229.   struct Window     *finestra1=NULL,
  230.                     *finestra2=NULL;
  231.   struct BitMap     immagine;
  232.   ULONG   i=0,j=0,r=0,g=0,b=0,riga=0;
  233.   UBYTE   cicli=0,numero_bytes=0,bytes_per_riga=0,num_piano=0;
  234.   UBYTE*  buffer=NULL;
  235.   UBYTE*  appo=NULL;
  236.   UBYTE*  indirizzo=NULL;
  237.   ULONG   general=0;
  238.   ULONG   dimens_buffer=DIM_RICERCA;
  239.   ULONG*  camg_data=NULL;
  240.  
  241.   fread ((char*)&general,1,4,finput);
  242.   // nota per fread: avremmo pututo scrivere anche fread(&general,4,1,finput)
  243.   // e non sarebbe cambiato nulla!
  244.   if (general != ID_IFF_FORM) return(-2);
  245.   fread ((char*)&general,1,4,finput);
  246.   if (general<dimens_buffer) dimens_buffer=general-4;
  247.   if ((buffer=AllocMem(dimens_buffer,MEMF_PUBLIC))==NULL) return(-3);
  248.   fread ((char*)&general,1,4,finput);
  249.   if (general != ID_IFF_ILBM) return(-4);
  250.   rewind (finput);
  251.   fread (buffer,1,dimens_buffer,finput);
  252.  
  253.   general=Find_Id(ID_IFF_BMHD,buffer,dimens_buffer);
  254.   if (general == -1 )
  255.    { FreeMem(buffer,dimens_buffer);
  256.      return(ERR_TIPO_FILE);
  257.    }
  258.   fseek(finput,general,SEEK_SET);
  259.   fread((char *)&bmhd,1,sizeof(struct chunk_bmhd),finput);
  260.   cmap=File_To_Buffer(finput,ID_IFF_CMAP,buffer,dimens_buffer);
  261.   camg=File_To_Buffer(finput,ID_IFF_CAMG,buffer,dimens_buffer);
  262.   body=File_To_Buffer(finput,ID_IFF_BODY,buffer,dimens_buffer);
  263.   if ((cmap)&&(body)&&(camg))
  264.   { if (bmhd.decodifica==1)   goto errore_2;
  265.     if (bmhd.compressione>1)  goto errore_2;
  266.     while((bmhd.lx_immagine % 16)) bmhd.lx_immagine++;
  267.     InitBitMap(&immagine,bmhd.piani,bmhd.lx_immagine,bmhd.ly_immagine);
  268.     //  void InitBimap(struct BitMap* bmp,LONG piani,LONG x,LONG y); (libreria graphics)
  269.     //  inizializza una struttura BitMap(che dovete avere già allocato in
  270.     //   memoria,occhio!).
  271.     //   bmp punta alla struttura bitmap
  272.     //   piani è il numero di bitplanes
  273.     //   x,y è la lunghezza e l'altezza in pixel dell'immagine da allocare.
  274.     for (i=0; i<bmhd.piani; i++)
  275.        if ((immagine.Planes[i]=AllocRaster(bmhd.lx_immagine,bmhd.ly_immagine))==NULL)
  276.        //  PLANEPTR AllocRaster(ULONG x,ULONG y)
  277.        //  AllocRaster alloca in CHIP ram un bitplane!
  278.        //  x,y sono la lunghezza e l'altezza in pixel dell'immagine
  279.        //  AllocRaster restituisce il puntatore al bitplane allocato in caso
  280.        //  di successo, 0 altrimenti!
  281.        //  Nota:AllocRaster converte il valore "x" al multiplo di 16 immediatamente
  282.        //  superiore al valore prefissato.
  283.         { for (j=0;j<i;j++) FreeRaster(immagine.Planes[j],bmhd.lx_immagine,bmhd.ly_immagine);
  284.         //  Void FreeRaster(PLANEPTR bpl,ULONG x,ULONG y);
  285.         //  FreeRaster librea il bitplane precedentemente allocato
  286.         //  bpl è il puntatore al bitplane
  287.         //  x,y sono la solita lunghezza e altezza del bitplane in pixel.
  288.           goto errore_2;
  289.         }
  290.     camg_data=(ULONG*)camg->buffer;
  291.     if ((schermo=(struct Screen*)OpenScreenTags(NULL,
  292.     SA_Width,bmhd.lx_schermo,    SA_Height,bmhd.ly_schermo,
  293.     SA_DisplayID,*camg_data,     SA_Depth,bmhd.piani,
  294.     SA_FullPalette,TRUE,         SA_Title,"IFF Reader V 1.0",
  295.     TAG_END,NULL))==NULL) goto errore_3;
  296.     //  Prendi quattro paghi uno! (neanche al supermercato :-)
  297.     //  struct Screen* OpenScreenTags(struct NewScreen* dati_schermo,Tag 1,...,Tag n)
  298.     //  struct Screen* OpenScreenTagList(struct NewScreen* dati_schermo,struct TagItem* taglist)
  299.     //  struct Window* OpenWindowTags(struct NewWindow* dati_finestra,Tag 1,...,Tag n)
  300.     //  struct Window* OpenWindowTagList(struct NewWindow* dati_finestra,struct TagItem* taglist)
  301.     //      (libreria INTUITION)
  302.     //  Aprono uno schermo (finestra) facendo uso dei Tags.
  303.     //  I Tags permettono di definire certi tipi di caratteristiche di
  304.     //  un oggetto senza dover memorizzare tali caratteristiche in una struttura
  305.     //  dati al momento della creazione dell'oggetto stesso.
  306.     //  Ad esempio, per arire uno schermo normalmente si definisce prima una struttura
  307.     //  NewScreen (es.struct NewScreen pippo={0,0,320,200,...} )
  308.     //  memorizzando all'interno tutti i dati necessari a definire
  309.     //  lo schermo che verrà aperto con la funzione schermo=Openscreen(&pippo).
  310.     //  Con i Tags otterremo sempre uno schermo solo che non impazziremo
  311.     //  nel sistemare al loro giusto posto le variabili nella struttura
  312.     //  inizializzatrice,settare flags,o perdere tempo in inizializzazioni
  313.     //  del tipo
  314.     //  pippo.Width =320;
  315.     //  pippo.Height=200;
  316.     //  ecc. ecc.
  317.     //  Grazie ai Tags potremo definire "al volo" i parametri che più ci interessano
  318.     //  e in qualsiasi ordine, facendoci risparmiare tempo e fatica!
  319.     //  Dimenticavo... i tags di immettono nel seguente modo :
  320.     //  ID_TAG1,valore_tag1,ID_TAG2,valore_tag2,.....,TAG_END,NULL,
  321.     //  oppure creando una struttura TagItem e definendo i tag nel seg. modo:
  322.     //  struct TagItem miei_tag_personali={
  323.     //         {ID_TAG1,valore_tag1},
  324.     //         {ID_TAG2,valore_tag2},
  325.     //         {...................},
  326.     //         {TAG_END,NULL};
  327.     //
  328.     //  OpenScreenTags(...) apre uno schermo con i tags
  329.     //  OpenScreenTagList(...) apre uno schermo con una TagList precedentemente definita.
  330.     //  in entrambe le funzioni è possibile definire anche una eventuale
  331.     //  struttura NewScreen di appoggio
  332.     //  Le funzioni restituiscono il puntatore della struttura schermo in
  333.     //  caso di successo,0 (NULL) in caso contrario.
  334.     //  Se volete saperne di più sui tags andate nella directory di include
  335.     //  del vostro compilatore C preferito, sotto la directory
  336.     //  "intuition/screens.h" studiatevi l'interminabile lista di tags
  337.     //  disponibili (e,dato che ci siete,anche la struttura NewScreen).
  338.     //  Per OpenWindow... il discorso è uguale, solo che al posto di avere
  339.     //  La struttura NewScreen abbiamo una struttura NewWindow e i tags
  340.     //  variano in modo differente.
  341.     //  Per strudiarvi i Tags delle finestre andate in "intuition/intuition.h"
  342.   appo=cmap->buffer;
  343.   for(i=0;i<(cmap->dimens/3);i++)
  344.   {
  345.     r=ULONG(*(appo++));
  346.     g=ULONG(*(appo++));
  347.     b=ULONG(*(appo++));
  348.     r+=r<<8;r+=r<<16;
  349.     g+=g<<8;g+=g<<16;
  350.     b+=b<<8;b+=b<<16;
  351.     SetRGB32(&schermo->ViewPort,i,r,g,b);
  352.     //  void SetRGB32(struct ViewPort* vp,ULONG,registro,ULONG r,ULONG g,ULONG,b);
  353.     //  questa funzione setta uno dei registri colore con la quantità
  354.     //  di rosso,verde,blu (valori ad 8 bit),indicati in "r","g","b".
  355.     //  L'unica cosa degna di nota è che i valori r,g,b, sono a 32 bit
  356.     //  e ciascuna componente contenere lo stesso valore del colore
  357.     //  per tutti e 4 i bytes che compongono la ULONG.
  358.     //  Es se devo settare r col valore 0x10 allora r dovrà contenere il
  359.     //  valore 0x10101010, altrimenti la funzione setrgb32 non funzionerà
  360.     //  correttamente.
  361.   }
  362.     bytes_per_riga=bmhd.lx_immagine/8;
  363.     appo=body->buffer;
  364.     for (riga=0;riga<bmhd.ly_immagine;riga++)
  365.     { for(num_piano=0;num_piano<bmhd.piani;num_piano++)
  366.        { indirizzo=immagine.Planes[num_piano]+bytes_per_riga*riga;
  367.            if (bmhd.compressione==1)
  368.            { numero_bytes=0;
  369.              while (numero_bytes<bytes_per_riga)
  370.              { cicli=UBYTE(*(appo++));
  371.                if ((cicli)>127)
  372.                { cicli=(-cicli)+1;
  373.                  for(i=0;i<cicli;i++,numero_bytes++,indirizzo++) *indirizzo=*appo;
  374.                  appo++;
  375.                }
  376.                else for(i=0;i<=cicli;i++,numero_bytes++) *(indirizzo++)=*(appo++);
  377.              }
  378.            }
  379.            else for(i=0;i<bytes_per_riga;i++) *(indirizzo++)=*(appo++);
  380.        }
  381.     }
  382.   if ((finestra2=(struct Window*)OpenWindowTags(NULL,
  383.   WA_Left ,0,                  WA_Top,0,
  384.   WA_Width,bmhd.lx_immagine,   WA_Height,bmhd.ly_immagine,
  385.   WA_SmartRefresh,TRUE,        WA_CustomScreen,schermo,
  386.   WA_Borderless,TRUE,          WA_Title,"IFF Output",
  387.   WA_SuperBitMap,&immagine,    TAG_END,NULL))==NULL) goto errore_3;
  388.   if ((finestra1=(struct Window*)OpenWindowTags(NULL,
  389.   WA_Left,0,                   WA_Top,0,
  390.   WA_Width,120,                WA_Height,15,
  391.   WA_DetailPen,1,              WA_BlockPen,0,
  392.   WA_IDCMP,IDCMP_CLOSEWINDOW,  WA_CustomScreen,schermo,
  393.   WA_CloseGadget,TRUE,         WA_DragBar,TRUE,
  394.   WA_Title,"<- Click ",        TAG_END,NULL))==NULL) goto errore_3;
  395.   if(finestra1)Wait(1L << finestra1->UserPort->mp_SigBit);
  396.   }
  397. errore_3:
  398.   if (finestra2) CloseWindow (finestra2);// Prima si chiudono sempre le
  399.   if (finestra1) CloseWindow (finestra1);// finestre poi lo schermo, altrimenti
  400.   if (schermo)   CloseScreen (schermo);  // si GURA!
  401.   // void CloseWindow(struct Window *finestra_da_chiudere);
  402.   // void CloseScreen(struct Screen *schermo_da_chiudere);
  403.   // Un giro sulle giostre a chi indovina a cosa servono queste due funzioni!
  404.   for (i=0;i<bmhd.piani;i++)// Liberiamo i bitplanes
  405.       FreeRaster (immagine.Planes[i],bmhd.lx_immagine,bmhd.ly_immagine);
  406. errore_2:
  407.   Dealloca_Buffers();
  408. errore_1:
  409.   if (buffer) FreeMem(buffer,dimens_buffer);
  410.   return(0);
  411. }
  412.  
  413.  
  414.  
  415.  
  416.  
  417.  
  418.  
  419.  
  420.  
  421.  
  422.  
  423.  
  424.  
  425.  
  426.  
  427.  
  428.  
  429.  
  430.  
  431.  
  432.  
  433.  
  434.  
  435.